fix(clerk-js): Suppress intermediate emissions from updateClient during setActive#7815
fix(clerk-js): Suppress intermediate emissions from updateClient during setActive#7815jacekradko wants to merge 3 commits intomainfrom
Conversation
…ng setActive During setActive, the touch() call triggers a piggybacked client update via BaseResource._baseFetch, which calls updateClient() and emits state to React before setTransitiveState() runs. With useSyncExternalStore (unlike the old useState+addListener approach), each emission causes a synchronous re-render. This exposed the new orgId to components before the transitive state (undefined) was set, causing flickering and stale data issues during org switches. Gate the #emit() in updateClient with the existing __internal_setActiveInProgress flag so intermediate state from piggybacked client updates is suppressed. setActive emits the final state itself via #setTransitiveState or #updateAccessors.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: f47d344 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
2b54404 to
d3a7b54
Compare
📝 WalkthroughWalkthroughA guard was added to Clerk's 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. No actionable comments were generated in the recent review. 🎉 Comment |
@clerk/agent-toolkit
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/dev-cli
@clerk/expo
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
|
!snapshot |
|
Hey @jacekradko - the snapshot version command generated the following package versions:
Tip: Use the snippet copy button below to quickly install the required packages. npm i @clerk/agent-toolkit@0.3.0-snapshot.v20260210223332 --save-exact
npm i @clerk/astro@3.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/backend@3.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/chrome-extension@3.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/clerk-js@6.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/dev-cli@1.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/expo@3.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/expo-passkeys@1.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/express@2.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/fastify@2.7.0-snapshot.v20260210223332 --save-exact
npm i @clerk/localizations@4.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/msw@0.0.1-snapshot.v20260210223332 --save-exact
npm i @clerk/nextjs@7.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/nuxt@2.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/react@6.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/react-router@3.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/shared@4.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/tanstack-react-start@1.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/testing@2.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/ui@1.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/upgrade@2.0.0-snapshot.v20260210223332 --save-exact
npm i @clerk/vue@2.0.0-snapshot.v20260210223332 --save-exact |
Summary
updateClientwhen called duringsetActive(e.g. fromtouch()'s piggybacked client response)undefined) is set during org switches__internal_setActiveInProgressflag to gate#emit()inupdateClientRoot Cause
During
setActive,touch()triggersupdateClient()viaBaseResource._baseFetchclient piggybacking, which calls#emit()before#setTransitiveState()runs. With the migration fromuseState+addListenertouseSyncExternalStore, each emission causes a synchronous re-render (sync-priority lane updates to prevent tearing). This exposed the new orgId to components before the transitive state was set, causing flickering during org switches.Emission sequence before fix:
updateClient#emit(newOrg)→setTransitiveState#emit(undefined)→#updateAccessors#emit(newOrg)Emission sequence after fix:
setTransitiveState#emit(undefined)→#updateAccessors#emit(newOrg)Test plan
pnpm buildpassesSummary by CodeRabbit
Bug Fixes
Tests